#include <algorithm>
#include <assert.h>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <vector>

#if defined(__INTELLISENSE__) || !defined(USE_CPP20_MODULES)
#include <vulkan/vulkan_raii.hpp>
#else
import vulkan_hpp;
#endif

#define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface.
#include <GLFW/glfw3.h>

constexpr uint32_t WIDTH = 800;
constexpr uint32_t HEIGHT = 600;

const std::vector<char const *> validationLayers = {
    "VK_LAYER_KHRONOS_validation"};

#ifdef NDEBUG
constexpr bool enableValidationLayers = false;
#else
constexpr bool enableValidationLayers = true;
#endif

class HelloTriangleApplication {
public:
  void run() {
    initWindow();
    initVulkan();
    mainLoop();
    cleanup();
  }

private:
  GLFWwindow *window = nullptr;
  vk::raii::Context context;
  vk::raii::Instance instance = nullptr;
  vk::raii::DebugUtilsMessengerEXT debugMessenger = nullptr;
  vk::raii::SurfaceKHR surface = nullptr;
  vk::raii::PhysicalDevice physicalDevice = nullptr;
  vk::raii::Device device = nullptr;
  uint32_t queueIndex = ~0;
  vk::raii::Queue queue = nullptr;
  vk::raii::SwapchainKHR swapChain = nullptr;
  std::vector<vk::Image> swapChainImages;
  vk::SurfaceFormatKHR swapChainSurfaceFormat;
  vk::Extent2D swapChainExtent;
  std::vector<vk::raii::ImageView> swapChainImageViews;

  vk::raii::PipelineLayout pipelineLayout = nullptr;
  vk::raii::Pipeline graphicsPipeline = nullptr;

  vk::raii::CommandPool commandPool = nullptr;
  vk::raii::CommandBuffer commandBuffer = nullptr;

  vk::raii::Semaphore presentCompleteSemaphore = nullptr;
  vk::raii::Semaphore renderFinishedSemaphore = nullptr;
  vk::raii::Fence drawFence = nullptr;

  std::vector<const char *> requiredDeviceExtension = {
      vk::KHRSwapchainExtensionName, vk::KHRSpirv14ExtensionName,
      vk::KHRSynchronization2ExtensionName,
      vk::KHRCreateRenderpass2ExtensionName
#if defined(__APPLE__) || defined(__MOLENGVK__)
      // 在苹果平台上，需要启用portability subset扩展
      ,
      "VK_KHR_portability_subset"
#endif
  };

  void initWindow() {
    glfwInit();

    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

    window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
  }

  void initVulkan() {
    createInstance();
    createSurface();
    pickPhysicalDevice();
    createLogicalDevice();
    createSwapChain();
    createImageViews();
    createGraphicsPipeline();
    createCommandPool();
    createCommandBuffer();
    createSyncObjects();
  }

  void mainLoop() {
    while (!glfwWindowShouldClose(window)) {
      glfwPollEvents();
      drawFrame();
    }

    device.waitIdle();
  }

  void cleanup() {
    glfwDestroyWindow(window);

    glfwTerminate();
  }

  void createInstance() {
    // 使用构造函数而不是 designated initializer
    vk::ApplicationInfo appInfo("Hello Triangle",         // pApplicationName
                                VK_MAKE_VERSION(1, 0, 0), // applicationVersion
                                "No Engine",              // pEngineName
                                VK_MAKE_VERSION(1, 0, 0), // engineVersion
                                vk::ApiVersion14          // apiVersion
    );

    // Get the required layers
    std::vector<char const *> requiredLayers;
    if (enableValidationLayers) {
      requiredLayers.assign(validationLayers.begin(), validationLayers.end());
    }

    // Check if the required layers are supported by the Vulkan implementation.
    auto layerProperties = context.enumerateInstanceLayerProperties();
    for (auto const &requiredLayer : requiredLayers) {
      // 打印验证的layer
      std::cout << "Checking layer: " << requiredLayer << std::endl;
      // 使用 C++20 的 std::ranges::none_of 算法
      // 检查 layerProperties 容器中是否没有任何元素满足 lambda 表达式的条件
      // lambda 表达式比较层属性中的 layerName 与 requiredLayer 是否相等
      // 使用 strcmp 进行字符串比较
      if (std::ranges::none_of(
              layerProperties, [requiredLayer](auto const &layerProperty) {
                return strcmp(layerProperty.layerName, requiredLayer) == 0;
              })) {
        throw std::runtime_error("Required layer not supported: " +
                                 std::string(requiredLayer));
      }
    }

    //获取所有需要的扩展
    auto requiredExtensions = getRequiredExtensions();
    // 检查是否支持验证扩展
    auto extensionProperties = context.enumerateInstanceExtensionProperties();
    for (auto const &requiredExtension : requiredExtensions) {
      // 打印验证的扩展
      std::cout << "Checking extension: " << requiredExtension << std::endl;
      if (std::ranges::none_of(
              extensionProperties,
              [requiredExtension](auto const &extensionProperty) {
                return strcmp(extensionProperty.extensionName,
                              requiredExtension) == 0;
              })) {
        throw std::runtime_error("Required extension not supported: " +
                                 std::string(requiredExtension));
      }
    }
    // 配置调试信使创建信息，在实例创建时就激活调试回调
    vk::DebugUtilsMessengerCreateInfoEXT debugCreateInfo;
    if (enableValidationLayers) {
      // 指定要捕获的消息严重级别：Verbose（详细信息）、Warning（警告）、Error（错误）
      vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(
          vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
          vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
          vk::DebugUtilsMessageSeverityFlagBitsEXT::eError);

      // 指定要捕获的消息类型：General（通用）、Performance（性能）、Validation（验证）
      vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(
          vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
          vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
          vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);

      // 创建调试信使的创建信息结构体
      debugCreateInfo = vk::DebugUtilsMessengerCreateInfoEXT{
          {}, severityFlags, messageTypeFlags, &debugCallback};
    }
    vk::InstanceCreateInfo createInfo(
#if defined(__APPLE__) || defined(__MOLENGVK__)
        static_cast<vk::InstanceCreateFlags>(
          //macos 上需要枚举可移植性层
            VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR),
#else
        {},
#endif
        &appInfo, static_cast<uint32_t>(requiredLayers.size()),
        requiredLayers.data(), static_cast<uint32_t>(requiredExtensions.size()),
        requiredExtensions.data());
    // 如果启用了验证层，将调试信使创建信息链接到实例创建信息的pNext链中
    if (enableValidationLayers) {
      createInfo.setPNext(&debugCreateInfo);
    }
    instance = vk::raii::Instance(context, createInfo);
  }

  void createSurface() {
    //在 Vulkan 中，window surface 是可选的。如果应用仅用于离屏渲染，则无需创建 surface。
    VkSurfaceKHR _surface;
    if (glfwCreateWindowSurface(*instance, window, nullptr, &_surface) != 0) {
      throw std::runtime_error("failed to create window surface!");
    }
    surface = vk::raii::SurfaceKHR(instance, _surface);
  }

  void pickPhysicalDevice() {
    // 打印所有支持的物理设备
    std::vector<vk::raii::PhysicalDevice> devices =
        instance.enumeratePhysicalDevices();
    for (auto const &device : devices) {
      std::cout << "Physical Device: " << device.getProperties().deviceName
                << std::endl;
    }
    const auto devIter = std::ranges::find_if(devices, [&](auto const &device) {
      //检查设备是否支持Vulkan 1.3 API版本
      bool supportsVulkan1_3 =
          device.getProperties().apiVersion >= VK_API_VERSION_1_3;

      //检查设备是否支持图形队列
      //对于设备的基础属性，如 name，设备类型和支持的 Vulkan 版本都可以通过 vkGetPhysicalDeviceProperties 查询。
      auto queueFamilies = device.getQueueFamilyProperties();
      bool supportsGraphics =
          std::ranges::any_of(queueFamilies, [](auto const &qfp) {
            return !!(qfp.queueFlags & vk::QueueFlagBits::eGraphics);
          });

      // 检查设备是否支持所有必需的设备扩展
      auto availableDeviceExtensions =
          device.enumerateDeviceExtensionProperties();
      // 打印所有可用的设备扩展
      for (auto const &availableDeviceExtension : availableDeviceExtensions) {
        std::cout << "Available Device Extension: "
                  << availableDeviceExtension.extensionName << std::endl;
      }
      bool supportsAllRequiredExtensions = std::ranges::all_of(
          requiredDeviceExtension,
          [&availableDeviceExtensions](auto const &requiredDeviceExtension) {
            return std::ranges::any_of(
                availableDeviceExtensions,
                [requiredDeviceExtension](
                    auto const &availableDeviceExtension) {
                  return strcmp(availableDeviceExtension.extensionName,
                                requiredDeviceExtension) == 0;
                });
          });
      //对于设备的可选特性，如纹理压缩、64 bit floats 等则可以通过 vkGetPhysicalDeviceFeatures 查询。
      auto features = device.template getFeatures2<
          vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan11Features,
          vk::PhysicalDeviceVulkan13Features,
          vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
      bool supportsRequiredFeatures =
          features.template get<vk::PhysicalDeviceVulkan11Features>()
              .shaderDrawParameters &&
          features.template get<vk::PhysicalDeviceVulkan13Features>()
              .synchronization2 &&
          features.template get<vk::PhysicalDeviceVulkan13Features>()
              .dynamicRendering &&
          features
              .template get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>()
              .extendedDynamicState;

      return supportsVulkan1_3 && supportsGraphics &&
             supportsAllRequiredExtensions && supportsRequiredFeatures;
    });
    if (devIter != devices.end()) {
      physicalDevice = *devIter;
    } else {
      throw std::runtime_error("failed to find a suitable GPU!");
    }
  }
  void printQueueFamilyFeatures(std::vector<vk::QueueFamilyProperties> queueFamilyProperties) {
    for (uint32_t i = 0; i < queueFamilyProperties.size(); ++i) {
    const auto& queueFamily = queueFamilyProperties[i];
    std::cout << "Queue Family " << i << ":\n";
    std::cout << "  Queue Count: " << queueFamily.queueCount << "\n";
    std::cout << "  Supported Operations:\n";

    if (queueFamily.queueFlags & vk::QueueFlagBits::eGraphics)
        std::cout << "    - Graphics\n";
    if (queueFamily.queueFlags & vk::QueueFlagBits::eCompute)
        std::cout << "    - Compute\n";
    if (queueFamily.queueFlags & vk::QueueFlagBits::eTransfer)
        std::cout << "    - Transfer\n";
    if (queueFamily.queueFlags & vk::QueueFlagBits::eSparseBinding)
        std::cout << "    - Sparse Binding\n";

    std::cout << "  Timestamp Valid Bits: " << queueFamily.timestampValidBits << "\n";
    std::cout << "  Min Image Timestamp Granularity: "
              << queueFamily.minImageTransferGranularity.width << "x"
              << queueFamily.minImageTransferGranularity.height << "x"
              << queueFamily.minImageTransferGranularity.depth << "\n";
}
  }
  void createLogicalDevice() {
    std::vector<vk::QueueFamilyProperties> queueFamilyProperties =
        physicalDevice.getQueueFamilyProperties();
    // 打印队列家族特征
    printQueueFamilyFeatures(queueFamilyProperties);
    // 找到一个支持graphics和present的队列家族
    for (uint32_t qfpIndex = 0; qfpIndex < queueFamilyProperties.size();
         qfpIndex++) {
      //QueueFamily满足graphics和present
      if ((queueFamilyProperties[qfpIndex].queueFlags &
           vk::QueueFlagBits::eGraphics) &&
           //查询硬件能力是否支持present
          physicalDevice.getSurfaceSupportKHR(qfpIndex, *surface)) {
        // found a queue family that supports both graphics and present
        queueIndex = qfpIndex;
        break;
      }
    }
    if (queueIndex == ~0) {
      throw std::runtime_error(
          "Could not find a queue for graphics and present -> terminating");
    }

    // 创建各个 feature 结构体
    vk::PhysicalDeviceFeatures2 features2{};
    vk::PhysicalDeviceVulkan11Features vulkan11Features{};
    vulkan11Features.shaderDrawParameters = true;
    vk::PhysicalDeviceVulkan13Features vulkan13Features{};
    vulkan13Features.synchronization2 = true;
    vulkan13Features.dynamicRendering = true;
    vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT
        extendedDynamicStateFeatures{};
    extendedDynamicStateFeatures.extendedDynamicState = true;

    // 手动链接结构体
    features2.pNext = &vulkan11Features;
    vulkan11Features.pNext = &vulkan13Features;
    vulkan13Features.pNext = &extendedDynamicStateFeatures;

    // create a Device
    //Queue 的优先级（范围为0∼1）等，优先级越高表示提示（并非绝对）驱动在资源经常时应该给这个 Queue 更多的时间片
    float queuePriority = 0.0f;
    vk::DeviceQueueCreateInfo deviceQueueCreateInfo(
        {},            // flags
        queueIndex,    // queueFamilyIndex
        1,             // queueCount
        &queuePriority // pQueuePriorities
    );

    vk::DeviceCreateInfo deviceCreateInfo(
        {},                     // flags
        1,                      // queueCreateInfoCount
        &deviceQueueCreateInfo, // pQueueCreateInfos
        0,                      // enabledLayerCount
        nullptr,                // ppEnabledLayerNames
        static_cast<uint32_t>(
            requiredDeviceExtension.size()), // enabledExtensionCount
        requiredDeviceExtension.data(),      // ppEnabledExtensionNames
        nullptr,                             // pEnabledFeatures
        &features2                           // pNext
    );

    device = vk::raii::Device(physicalDevice, deviceCreateInfo);
    queue = vk::raii::Queue(device, queueIndex, 0);
  }

  void createSwapChain() {
    auto surfaceCapabilities =
        physicalDevice.getSurfaceCapabilitiesKHR(*surface);
    swapChainExtent = chooseSwapExtent(surfaceCapabilities);
    swapChainSurfaceFormat =
        chooseSwapSurfaceFormat(physicalDevice.getSurfaceFormatsKHR(*surface));

    vk::SwapchainCreateInfoKHR swapChainCreateInfo(
        {},                                           // flags
        *surface,                                     // surface
        chooseSwapMinImageCount(surfaceCapabilities), // minImageCount
        swapChainSurfaceFormat.format,                // imageFormat
        swapChainSurfaceFormat.colorSpace,            // imageColorSpace
        swapChainExtent,                              // imageExtent
        1,                                            // imageArrayLayers
        vk::ImageUsageFlagBits::eColorAttachment,     // imageUsage
        vk::SharingMode::eExclusive,                  // imageSharingMode
        0,                                            // queueFamilyIndexCount
        nullptr,                                      // pQueueFamilyIndices
        surfaceCapabilities.currentTransform,         // preTransform
        vk::CompositeAlphaFlagBitsKHR::eOpaque,       // compositeAlpha
        chooseSwapPresentMode(
            physicalDevice.getSurfacePresentModesKHR(*surface)), // presentMode
        true                                                     // clipped
    );

    swapChain = vk::raii::SwapchainKHR(device, swapChainCreateInfo);
    swapChainImages = swapChain.getImages();
  }

  void createImageViews() {
    assert(swapChainImageViews.empty());

    vk::ComponentMapping components(
        vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity,
        vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity);
    vk::ImageSubresourceRange subresourceRange(vk::ImageAspectFlagBits::eColor,
                                               0, 1, 0, 1);

    for (auto &image : swapChainImages) {
      vk::ImageViewCreateInfo imageViewCreateInfo(
          {},                            // flags
          image,                         // image
          vk::ImageViewType::e2D,        // viewType
          swapChainSurfaceFormat.format, // format
          components,                    // components
          subresourceRange               // subresourceRange
      );
      swapChainImageViews.emplace_back(device, imageViewCreateInfo);
    }
  }

  void createGraphicsPipeline() {
    vk::raii::ShaderModule shaderModule =
        createShaderModule(readFile("shaders/slang.spv"));

    vk::PipelineShaderStageCreateInfo vertShaderStageInfo(
        {},                               // flags
        vk::ShaderStageFlagBits::eVertex, // stage
        shaderModule,                     // module
        "vertMain"                        // pName
    );
    vk::PipelineShaderStageCreateInfo fragShaderStageInfo(
        {},                                 // flags
        vk::ShaderStageFlagBits::eFragment, // stage
        shaderModule,                       // module
        "fragMain"                          // pName
    );
    vk::PipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo,
                                                        fragShaderStageInfo};

    vk::PipelineVertexInputStateCreateInfo vertexInputInfo;
    vk::PipelineInputAssemblyStateCreateInfo inputAssembly(
        {},                                  // flags
        vk::PrimitiveTopology::eTriangleList // topology
    );
    vk::PipelineViewportStateCreateInfo viewportState({},      // flags
                                                      1,       // viewportCount
                                                      nullptr, // pViewports
                                                      1,       // scissorCount
                                                      nullptr  // pScissors
    );

    vk::PipelineRasterizationStateCreateInfo rasterizer(
        {},                          // flags
        vk::False,                   // depthClampEnable
        vk::False,                   // rasterizerDiscardEnable
        vk::PolygonMode::eFill,      // polygonMode
        vk::CullModeFlagBits::eBack, // cullMode
        vk::FrontFace::eClockwise,   // frontFace
        vk::False,                   // depthBiasEnable
        0.0f,                        // depthBiasConstantFactor
        0.0f,                        // depthBiasClamp
        1.0f,                        // depthBiasSlopeFactor
        1.0f                         // lineWidth
    );

    vk::PipelineMultisampleStateCreateInfo multisampling(
        {},                          // flags
        vk::SampleCountFlagBits::e1, // rasterizationSamples
        vk::False                    // sampleShadingEnable
    );

    vk::PipelineColorBlendAttachmentState colorBlendAttachment(
        vk::False,              // blendEnable
        vk::BlendFactor::eOne,  // srcColorBlendFactor
        vk::BlendFactor::eZero, // dstColorBlendFactor
        vk::BlendOp::eAdd,      // colorBlendOp
        vk::BlendFactor::eOne,  // srcAlphaBlendFactor
        vk::BlendFactor::eZero, // dstAlphaBlendFactor
        vk::BlendOp::eAdd,      // alphaBlendOp
        vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
            vk::ColorComponentFlagBits::eB |
            vk::ColorComponentFlagBits::eA // colorWriteMask
    );

    vk::PipelineColorBlendStateCreateInfo colorBlending(
        {},                   // flags
        vk::False,            // logicOpEnable
        vk::LogicOp::eCopy,   // logicOp
        1,                    // attachmentCount
        &colorBlendAttachment // pAttachments
    );

    std::vector dynamicStates = {vk::DynamicState::eViewport,
                                 vk::DynamicState::eScissor};
    vk::PipelineDynamicStateCreateInfo dynamicState(
        {},                                          // flags
        static_cast<uint32_t>(dynamicStates.size()), // dynamicStateCount
        dynamicStates.data()                         // pDynamicStates
    );

    vk::PipelineLayoutCreateInfo pipelineLayoutInfo(
        {},      // flags
        0,       // setLayoutCount
        nullptr, // pSetLayouts
        0,       // pushConstantRangeCount
        nullptr  // pPushConstantRanges
    );

    pipelineLayout = vk::raii::PipelineLayout(device, pipelineLayoutInfo);

    // 创建 PipelineRenderingCreateInfo
    vk::PipelineRenderingCreateInfo pipelineRenderingCreateInfo(
        {},                            // flags
        1,                             // colorAttachmentCount
        &swapChainSurfaceFormat.format // pColorAttachmentFormats
    );

    vk::GraphicsPipelineCreateInfo pipelineCreateInfo(
        {},                          // flags
        2,                           // stageCount
        shaderStages,                // pStages
        &vertexInputInfo,            // pVertexInputState
        &inputAssembly,              // pInputAssemblyState
        nullptr,                     // pTessellationState
        &viewportState,              // pViewportState
        &rasterizer,                 // pRasterizationState
        &multisampling,              // pMultisampleState
        nullptr,                     // pDepthStencilState
        &colorBlending,              // pColorBlendState
        &dynamicState,               // pDynamicState
        pipelineLayout,              // layout
        nullptr,                     // renderPass
        0,                           // subpass
        nullptr,                     // basePipelineHandle
        -1,                          // basePipelineIndex
        &pipelineRenderingCreateInfo // pNext
    );

    graphicsPipeline = vk::raii::Pipeline(device, nullptr, pipelineCreateInfo);
  }

  void createCommandPool() {
    vk::CommandPoolCreateInfo poolInfo(
        vk::CommandPoolCreateFlagBits::eResetCommandBuffer, // flags
        queueIndex                                          // queueFamilyIndex
    );
    commandPool = vk::raii::CommandPool(device, poolInfo);
  }

  void createCommandBuffer() {
    vk::CommandBufferAllocateInfo allocInfo(
        commandPool,                      // commandPool
        vk::CommandBufferLevel::ePrimary, // level
        1                                 // commandBufferCount
    );
    commandBuffer =
        std::move(vk::raii::CommandBuffers(device, allocInfo).front());
  }

  void recordCommandBuffer(uint32_t imageIndex) {
    commandBuffer.begin({});
    // Before starting rendering, transition the swapchain image to
    // COLOR_ATTACHMENT_OPTIMAL
    transition_image_layout(
        imageIndex, vk::ImageLayout::eUndefined,
        vk::ImageLayout::eColorAttachmentOptimal,
        {}, // srcAccessMask (no need to wait for previous operations)
        vk::AccessFlagBits2::eColorAttachmentWrite,        // dstAccessMask
        vk::PipelineStageFlagBits2::eTopOfPipe,            // srcStage
        vk::PipelineStageFlagBits2::eColorAttachmentOutput // dstStage
    );
    vk::ClearValue clearColor = vk::ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f);

    vk::RenderingAttachmentInfo attachmentInfo(
        swapChainImageViews[imageIndex],          // imageView
        vk::ImageLayout::eColorAttachmentOptimal, // imageLayout
        {},                                       // resolveMode
        nullptr,                                  // resolveImageView
        vk::ImageLayout::eUndefined,              // resolveImageLayout
        vk::AttachmentLoadOp::eClear,             // loadOp
        vk::AttachmentStoreOp::eStore,            // storeOp
        clearColor                                // clearValue
    );

    vk::Offset2D renderOffset(0, 0);
    vk::Rect2D renderArea(renderOffset, swapChainExtent);
    vk::RenderingInfo renderingInfo({},              // flags
                                    renderArea,      // renderArea
                                    1,               // layerCount
                                    0,               // viewMask
                                    1,               // colorAttachmentCount
                                    &attachmentInfo, // pColorAttachments
                                    nullptr,         // pDepthAttachment
                                    nullptr          // pStencilAttachment
    );

    commandBuffer.beginRendering(renderingInfo);
    commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics,
                               *graphicsPipeline);
    commandBuffer.setViewport(
        0,
        vk::Viewport(0.0f, 0.0f, static_cast<float>(swapChainExtent.width),
                     static_cast<float>(swapChainExtent.height), 0.0f, 1.0f));
    commandBuffer.setScissor(0,
                             vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent));
    commandBuffer.draw(3, 1, 0, 0);

    commandBuffer.endRendering();
    // After rendering, transition the swapchain image to PRESENT_SRC
    transition_image_layout(
        imageIndex, vk::ImageLayout::eColorAttachmentOptimal,
        vk::ImageLayout::ePresentSrcKHR,
        vk::AccessFlagBits2::eColorAttachmentWrite,         // srcAccessMask
        {},                                                 // dstAccessMask
        vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage
        vk::PipelineStageFlagBits2::eBottomOfPipe           // dstStage
    );
    commandBuffer.end();
  }

  void transition_image_layout(uint32_t currentFrame,
                               vk::ImageLayout old_layout,
                               vk::ImageLayout new_layout,
                               vk::AccessFlags2 src_access_mask,
                               vk::AccessFlags2 dst_access_mask,
                               vk::PipelineStageFlags2 src_stage_mask,
                               vk::PipelineStageFlags2 dst_stage_mask) {

    // 创建 subresourceRange
    vk::ImageSubresourceRange subresourceRange;
    subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
    subresourceRange.baseMipLevel = 0;
    subresourceRange.levelCount = 1;
    subresourceRange.baseArrayLayer = 0;
    subresourceRange.layerCount = 1;

    // 创建 ImageMemoryBarrier2
    vk::ImageMemoryBarrier2 barrier;
    barrier.srcStageMask = src_stage_mask;
    barrier.srcAccessMask = src_access_mask;
    barrier.dstStageMask = dst_stage_mask;
    barrier.dstAccessMask = dst_access_mask;
    barrier.oldLayout = old_layout;
    barrier.newLayout = new_layout;
    barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    barrier.image = swapChainImages[currentFrame];
    barrier.subresourceRange = subresourceRange;

    // 创建 DependencyInfo
    vk::DependencyInfo dependency_info;
    dependency_info.dependencyFlags = {};
    dependency_info.imageMemoryBarrierCount = 1;
    dependency_info.pImageMemoryBarriers = &barrier;

    commandBuffer.pipelineBarrier2(dependency_info);
  }

  void createSyncObjects() {
    presentCompleteSemaphore =
        vk::raii::Semaphore(device, vk::SemaphoreCreateInfo());
    renderFinishedSemaphore =
        vk::raii::Semaphore(device, vk::SemaphoreCreateInfo());
    drawFence = vk::raii::Fence(
        device, vk::FenceCreateInfo(vk::FenceCreateFlagBits::eSignaled));
  }

  void drawFrame() {
    queue.waitIdle();

    auto [result, imageIndex] = swapChain.acquireNextImage(
        UINT64_MAX, *presentCompleteSemaphore, nullptr);
    recordCommandBuffer(imageIndex);

    device.resetFences(*drawFence);
    vk::PipelineStageFlags waitDestinationStageMask(
        vk::PipelineStageFlagBits::eColorAttachmentOutput);

    vk::SubmitInfo submitInfo;
    submitInfo.waitSemaphoreCount = 1;
    submitInfo.pWaitSemaphores = &*presentCompleteSemaphore;
    submitInfo.pWaitDstStageMask = &waitDestinationStageMask;
    submitInfo.commandBufferCount = 1;
    submitInfo.pCommandBuffers = &*commandBuffer;
    submitInfo.signalSemaphoreCount = 1;
    submitInfo.pSignalSemaphores = &*renderFinishedSemaphore;

    queue.submit(submitInfo, *drawFence);
    while (vk::Result::eTimeout ==
           device.waitForFences(*drawFence, vk::True, UINT64_MAX))
      ;

    // 使用默认构造+成员赋值的方式，避免构造函数参数顺序问题
    vk::PresentInfoKHR presentInfoKHR{};
    presentInfoKHR.waitSemaphoreCount = 1;
    presentInfoKHR.pWaitSemaphores = &*renderFinishedSemaphore;
    presentInfoKHR.swapchainCount = 1;
    presentInfoKHR.pSwapchains = &*swapChain;
    presentInfoKHR.pImageIndices = &imageIndex;

    result = queue.presentKHR(presentInfoKHR);
    switch (result) {
    case vk::Result::eSuccess:
      break;
    case vk::Result::eSuboptimalKHR:
      std::cout
          << "vk::Queue::presentKHR returned vk::Result::eSuboptimalKHR !\n";
      break;
    default:
      break; // an unexpected result is returned!
    }
  }

  [[nodiscard]] vk::raii::ShaderModule
  createShaderModule(const std::vector<char> &code) const {
    // 使用默认构造+成员赋值的方式，避免构造函数参数顺序问题
    vk::ShaderModuleCreateInfo createInfo{};
    createInfo.codeSize = code.size() * sizeof(char);
    createInfo.pCode = reinterpret_cast<const uint32_t *>(code.data());

    // 直接返回构造的对象，避免拷贝构造函数问题
    return vk::raii::ShaderModule{device, createInfo};
  }

  static uint32_t chooseSwapMinImageCount(
      vk::SurfaceCapabilitiesKHR const &surfaceCapabilities) {
    auto minImageCount = std::max(3u, surfaceCapabilities.minImageCount);
    if ((0 < surfaceCapabilities.maxImageCount) &&
        (surfaceCapabilities.maxImageCount < minImageCount)) {
      minImageCount = surfaceCapabilities.maxImageCount;
    }
    return minImageCount;
  }

  static vk::SurfaceFormatKHR chooseSwapSurfaceFormat(
      const std::vector<vk::SurfaceFormatKHR> &availableFormats) {
    assert(!availableFormats.empty());
    const auto formatIt =
        std::ranges::find_if(availableFormats, [](const auto &format) {
          return format.format == vk::Format::eB8G8R8A8Srgb &&
                 format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear;
        });
    return formatIt != availableFormats.end() ? *formatIt : availableFormats[0];
  }

  static vk::PresentModeKHR chooseSwapPresentMode(
      const std::vector<vk::PresentModeKHR> &availablePresentModes) {
    assert(std::ranges::any_of(availablePresentModes, [](auto presentMode) {
      return presentMode == vk::PresentModeKHR::eFifo;
    }));
    return std::ranges::any_of(availablePresentModes,
                               [](const vk::PresentModeKHR value) {
                                 return vk::PresentModeKHR::eMailbox == value;
                               })
               ? vk::PresentModeKHR::eMailbox
               : vk::PresentModeKHR::eFifo;
  }

  vk::Extent2D
  chooseSwapExtent(const vk::SurfaceCapabilitiesKHR &capabilities) {
    if (capabilities.currentExtent.width != 0xFFFFFFFF) {
      return capabilities.currentExtent;
    }
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);

    return {std::clamp<uint32_t>(width, capabilities.minImageExtent.width,
                                 capabilities.maxImageExtent.width),
            std::clamp<uint32_t>(height, capabilities.minImageExtent.height,
                                 capabilities.maxImageExtent.height)};
  }

  std::vector<const char *> getRequiredExtensions() {
    uint32_t glfwExtensionCount = 0;
    auto glfwExtensions =
        glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

    std::vector extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
    if (enableValidationLayers) {
      extensions.push_back(vk::EXTDebugUtilsExtensionName);
    }
#if defined(__APPLE__) || defined(__MOLENGVK__)
    // macos 上需要枚举可移植性层
    extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
    return extensions;
  }
  // 调试回调函数：被 Vulkan 验证层调用，用于输出调试信息
  // VKAPI_ATTR 和 VKAPI_CALL 确保使用 Vulkan 所需的调用约定
  static VKAPI_ATTR vk::Bool32 VKAPI_CALL debugCallback(
      vk::DebugUtilsMessageSeverityFlagBitsEXT severity, // 消息严重程度
      vk::DebugUtilsMessageTypeFlagsEXT type,            // 消息类型
      const vk::DebugUtilsMessengerCallbackDataEXT
          *pCallbackData, // 包含消息详细信息的结构体指针
      void *pUserData     // 应用层传递的用户数据指针，未使用
  ) {
    // if (severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eError ||
    //     severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning) {
    std::cerr << "validation layer: type " << to_string(type)
              << " msg: " << pCallbackData->pMessage << std::endl;
    // }
    // 返回 vk::False 表示该消息未被应用层“处理”，Vulkan 将继续传递该消息
    return vk::False;
  }

  static std::vector<char> readFile(const std::string &filename) {
    std::ifstream file(filename, std::ios::ate | std::ios::binary);
    if (!file.is_open()) {
      throw std::runtime_error("failed to open file!");
    }
    std::vector<char> buffer(file.tellg());
    file.seekg(0, std::ios::beg);
    file.read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
    file.close();
    return buffer;
  }
};

int main() {
  try {
    HelloTriangleApplication app;
    app.run();
  } catch (const std::exception &e) {
    std::cerr << e.what() << std::endl;
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}